#include "client.h"
#include <sstream>
#include <algorithm>
#include <chrono>
#include <errno.h>
#include <cstdio> // For perror

ChatClient::ChatClient(const char* ip, uint16_t port)
    : running(false)
{
    client_socket = std::make_shared<Socket>(); // 创建客户端Socket
    server_addr = std::make_shared<InetAddress>(ip, port); // 创建服务器地址
}

ChatClient::~ChatClient()
{
    running = false; // 设置停止标志，通知所有线程退出
    send_queue_cv.notify_all(); // 唤醒网络IO线程，使其检查running状态并退出

    if (network_io_thread.joinable())
    {
        network_io_thread.join(); // 等待网络IO线程结束
    }
    if (input_thread.joinable())
    {
        input_thread.join(); // 等待用户输入线程结束
    }
    
    // 确保 Socket 在线程结束后被关闭
    if (client_socket->getFd() != -1) {
        close(client_socket->getFd());
    }
    std::cout << "客户端已关闭。" << std::endl;
}

bool ChatClient::connectToServer()
{
    if (::connect(client_socket->getFd(), (sockaddr*)&server_addr->addr, server_addr->addr_len) < 0)
    {
        perror("connect error");
        return false;
    }
    std::cout << "成功连接到服务器: " 
              << inet_ntoa(server_addr->addr.sin_addr) << ":" 
              << ntohs(server_addr->addr.sin_port) << std::endl;
    
    client_socket->setnonblocking(); // 连接成功后，将客户端 Socket 设置为非阻塞模式
    return true;
}

// ============== 网络 I/O 线程函数 ==============
void ChatClient::networkIoLoop()
{
    char buffer[BUFSIZ];
    std::string received_buffer;

    while (running)
    {
        // --- 接收数据 ---
        ssize_t bytes_recv = recv(client_socket->getFd(), buffer, sizeof(buffer) - 1, 0);
        if (bytes_recv > 0)
        {
            buffer[bytes_recv] = '\0';
            received_buffer += buffer;

            size_t pos;
            while ((pos = received_buffer.find('\n')) != std::string::npos) {
                std::string full_message = received_buffer.substr(0, pos);
                received_buffer.erase(0, pos + 1);

                if (!full_message.empty() && full_message.back() == '\r') {
                    full_message.pop_back();
                }
                
                std::lock_guard<std::mutex> lock(recv_queue_mutex);
                recv_message_queue.push(full_message);
            }
        }
        else if (bytes_recv == 0)
        {
            std::cout << "服务器已关闭连接。" << std::endl;
            running = false; // 服务器断开，停止所有线程
            break;
        }
        else if (bytes_recv < 0)
        {
            if (errno == EINTR) {
                continue;
            } else if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 没有数据可读，继续检查发送队列
            } else {
                perror("recv error");
                running = false;
                break;
            }
        }

        // --- 发送数据 ---
        // 使用条件变量等待，避免忙等，并在有数据或停止运行时唤醒
        std::unique_lock<std::mutex> lock(send_queue_mutex);
        send_queue_cv.wait_for(lock, std::chrono::milliseconds(10), [this]{ return !send_message_queue.empty() || !running; });
        
        if (!running) break; // 如果在等待时被通知停止，则退出

        while (!send_message_queue.empty())
        {
            std::string message_to_send = send_message_queue.front();
            lock.unlock(); // 发送操作不需要持有锁，先解锁，避免阻塞其他线程
            
            // 确保消息以换行符结尾
            if (message_to_send.empty() || message_to_send.back() != '\n')
            {
                message_to_send += '\n';
            }

            size_t total_sent = 0;
            size_t message_len = message_to_send.length();
            while (running && total_sent < message_len) { // 增加running检查
                ssize_t bytes_sent = ::send(client_socket->getFd(), message_to_send.c_str() + total_sent, message_len - total_sent, 0);
                if (bytes_sent < 0) {
                    if (errno == EAGAIN || errno == EWOULDBLOCK) {
                        std::this_thread::sleep_for(std::chrono::milliseconds(10));
                        continue;
                    } else if (errno == EINTR) {
                        continue;
                    } else {
                        perror("send error");
                        std::cerr << "发送消息失败，连接可能已断开。终止客户端。" << std::endl;
                        running = false; // 假设连接已断开
                        break; // 退出发送循环
                    }
                } else if (bytes_sent == 0) {
                    std::cerr << "对端已关闭连接。终止客户端。" << std::endl;
                    running = false;
                    break;
                }
                total_sent += bytes_sent;
            }

            if (!running) break; // 如果发送过程中停止运行，则退出外层循环
            
            lock.lock(); // 重新加锁以访问队列
            send_message_queue.pop();
        }
    }
}

// ============== 用户输入线程函数 ==============
void ChatClient::getUserInput() {
    std::string line;
    while (running) {
        std::cout << "> " << std::flush; // 提示用户输入
        std::getline(std::cin, line); // 阻塞读取用户输入

        if (std::cin.eof() || std::cin.fail()) {
            std::cerr << "输入流关闭或出错，退出输入线程。" << std::endl;
            running = false;
            break;
        }

        if (line == "exit") {
            running = false;
            break;
        }
        
        queueMessageToSend(line); // 将用户输入放入发送队列
    }
    send_queue_cv.notify_one(); // 通知网络IO线程，即使没有新数据，也让它醒来检查 running 状态
}

// ============== 主循环函数 ==============
void ChatClient::run()
{
    if (!connectToServer())
    {
        return;
    }

    running = true;
    network_io_thread = std::thread(&ChatClient::networkIoLoop, this); // 启动网络IO线程
    input_thread = std::thread(&ChatClient::getUserInput, this);      // 启动用户输入线程

    std::cout << "欢迎来到聊天室！" << std::endl;

    while (running)
    {
        // 持续检查并打印接收到的网络消息
        while (hasReceivedMessages()) {
            std::string msg = getReceivedMessage();
            // 在打印消息前，将光标移到行首，清除当前行（如果用户正在输入），再打印消息
            // 然后重新打印'> '提示符
            std::cout << "\r" << std::string(80, ' ') << "\r" // 清除当前行
                      << msg << std::endl
                      << "> " << std::flush;
        }

        // 主线程可以短暂休眠，避免忙等，但主要任务是检查队列和协调退出
        if (!running && !hasReceivedMessages()) { // 避免在有消息待处理时休眠
             break; // 退出主循环
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
    }
    
    // 退出主循环后，确保所有线程都已结束
    if (network_io_thread.joinable()) {
        network_io_thread.join();
    }
    if (input_thread.joinable()) {
        input_thread.join();
    }
}

// ============== 消息队列访问函数 ==============
std::string ChatClient::getReceivedMessage()
{
    std::lock_guard<std::mutex> lock(recv_queue_mutex);
    std::string msg = recv_message_queue.front();
    recv_message_queue.pop();
    return msg;
}

bool ChatClient::hasReceivedMessages()
{
    std::lock_guard<std::mutex> lock(recv_queue_mutex);
    return !recv_message_queue.empty();
}

void ChatClient::queueMessageToSend(const std::string& message)
{
    {
        std::lock_guard<std::mutex> lock(send_queue_mutex);
        send_message_queue.push(message);
    }
    send_queue_cv.notify_one(); // 通知网络I/O线程有新消息待发送
}

int main(int argc, char* argv[])
{
    const char* ip = "127.0.0.1";
    uint16_t port = 8080;

    if (argc > 1) {
        ip = argv[1];
    }
    if (argc > 2) {
        port = static_cast<uint16_t>(std::stoi(argv[2]));
    }

    ChatClient client(ip, port);
    client.run();

    return 0;
}